package com.candy.common.utils;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * 通用工具类
 * @author rong xi
 * @version 1.0
 * @date 2023/09/21 11:52
 */
@Slf4j
public class CommonUtil {

    /**
     * 列表导出方法
     * @param fileName 文件名
     * @param dataList 数据
     * @param clazz 对象class
     *
     */
    @SneakyThrows
    public static <T> void exportExcel(String fileName,List<T> dataList,Class<T> clazz){
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        Optional.ofNullable(((ServletRequestAttributes)requestAttributes).getResponse())
                .ifPresent(response->{
                    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                    response.setCharacterEncoding("utf-8");
                    String encodeFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
                    response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName + ".xlsx");
                    try {
                        EasyExcel.write(response.getOutputStream(), clazz).sheet(fileName).doWrite(dataList);
                    } catch (IOException e) {
                        log.error("导出excel异常:",e);
                        throw new RuntimeException(e);
                    }
                });

    }

    /**
     * 获取ip地址
     *
     * @param request 请求
     * @return ip地址
     */
    public static String getRequestIp(HttpServletRequest request){
        return Stream.of("X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR")
                //获取代理ip
                .filter(i->NetUtil.isUnknown(request.getHeader(i)))
                .findAny()
                //获取请求ip
                .or(()->Optional.of(request.getRemoteAddr()).filter(ip->!"127.0.0.1".equals(ip) && !"0:0:0:0:0:0:0:1".equals(ip)))
                //获取本地网卡ip
                .or(()->Optional.of(request.getRemoteAddr())
                        .map(r->{
                            try {
                                return Optional.ofNullable(InetAddress.getLocalHost())
                                        .map(InetAddress::getHostAddress)
                                        .orElse(null);
                            } catch (UnknownHostException e) {
                                log.error("获取网卡异常:",e);
                                return null;
                            }
                        }))

                .map(NetUtil::getMultistageReverseProxyIp)
                .orElse("未知IP");

    }

    /**
     * 是否为Multipart类型表单，此类型表单用于文件上传
     *
     * @param request 请求对象{@link HttpServletRequest}
     * @return 是否为Multipart类型表单，此类型表单用于文件上传
     */
    public static boolean isMultipart(HttpServletRequest request) {
        return Optional.ofNullable(request)
                //必须是POST
                .filter(r->"POST".equals(r.getMethod()))
                //contentType不能为空
                .filter(c->StrUtil.isNotBlank(c.getContentType()))
                //文件类型
                .filter(s->s.getContentType().toLowerCase().startsWith("multipart/"))
                .map((d)->Boolean.TRUE)
                .orElse(Boolean.FALSE);
    }

    /**
     * 对象不为空则执行方法
     *
     * @param obj 对象
     * @param consumer 消费方法
     * @param <T> 对象类型
     */
    public static <T> void notNullThen(T obj, Consumer<T> consumer){
        if(ObjectUtil.isNotNull(obj)){
            consumer.accept(obj);
        }
    }

    public static <T> void predicateConsumer (T obj,Predicate<T> predicate,Consumer<T> consumer){
        if(predicate.test(obj)){
            consumer.accept(obj);
        }
    }

    public static <T> void predicateConsumer (T obj,Predicate<T> predicate,Consumer<T> consumer,Consumer<T> consumerElse){
        if(predicate.test(obj)){
            consumer.accept(obj);
        }else{
            consumerElse.accept(obj);
        }
    }

    public static <T,R> R predicateFunction (T obj,Predicate<T> predicate,Function<T,R> function,Function<T,R> functionElse){
        if(predicate.test(obj)){
            return function.apply(obj);
        }
            return functionElse.apply(obj);
    }

}
